﻿using BepuUtilities;
using Meow.Core;
using Meow.Core.Graphics;
using Meow.Core.Input;
using Meow.Core.Simulation;
using Microsoft.Xna.Framework.Graphics;
using Myra;
using Myra.Graphics2D.UI;
using System.Numerics;
using System.Runtime.CompilerServices;


namespace TestDemo;

internal class DemoManagerScene : Scene
{
    public readonly string NAME = "Main";
    Engine engine;

    /// <summary>
    /// UI : Myra Desktop
    /// </summary>
    Desktop _desktop;
    Image background;

    /// <summary>
    /// UI root widget
    /// </summary>
    public Func<Widget> RootWidget;
    public SpriteBatch SpriteBatch;
    Label testLabel;

    public DemoManagerScene(Engine engine) : base(engine)
    {
        this.engine = engine;
    }

    public override void LoadContents()
    {
        base.LoadContents();

        // use this.Content to load your game content here
        MyraEnvironment.Game = engine;
        MyraEnvironment.EnableModalDarkening = true;
        _desktop = new Desktop();
        SpriteBatch = new SpriteBatch(engine.GraphicsDevice);

    }

    public override void BeginRun()
    {
        Screen.ShowCursor = true;
        InputHandler.LockTheMouse = false;

        RenderSystems.Add(new UpdateRenderableBoundingSys(World, this));
        RenderSystems.Add(new CameraPrepareForRenderSys(World, this));
        RenderSystems.Add(new CameraRenderSystem(World, this));

        //testScene.TickSystems.Add(new test_RotateEverythingSystem(testScene.World, testScene));
        UpdateSystems.Add(new test_RotateEverythingUpdateSystem(World, this));

        var matDef = new BlinnPhoneMaterial();
        MaterialCache.LoadAndAddDefine("BlinnPhone", matDef, Content);

        var texture = Content.Load<Texture2D>("DemoAssets/meow2");
        TextureCache.AddTexture("meow2", texture);

        var material = new Mti_BlinnPhone(matDef)
        {
            MainTexture = texture,
        };
        
        MaterialCache.AddMaterial("t1", material);

        var ent= World.Create(
            new C_Position() { Value = Vector3.Zero },
            new C_Rotation() { Value = Quaternion.Identity },
            new C_Scale() { Value = Vector3.One * 5f },
            new C_Renderable() { LocalBoundingSphere = MeshCache.FallbackMesh.BoundingSphere },
            new WithMesh() { mesh = MeshCache.FallbackMesh, material = material, Offset = Vector3.Zero }

            );

        var cam = new SimpleCamera(
            (float)Application.GraphicsDevice.Viewport.Width / (float)Application.GraphicsDevice.Viewport.Height,
            MathHelper.ToRadians(60), 0.2f, 1500f,
            new Viewport(0, 0, Screen.Width, Screen.Height / 2));
        cam.Position = new Vector3(10, 6, 0);
        cam.LookAt(Vector3.Zero);
        World.Create(
            cam
            );

        var cam2 = new SimpleCamera(
                (float)Application.GraphicsDevice.Viewport.Width / (float)Application.GraphicsDevice.Viewport.Height,
                MathHelper.ToRadians(60), 0.2f, 1500f, new Viewport(0, Screen.Height / 2, Screen.Width / 2, Screen.Height / 2));
        cam2.Position = new Vector3(-6.5f, 8, 0);
        cam2.LookAt(Vector3.Zero);
        World.Create(
            cam2
            );

        // ui test
        var panel = new Panel();

        background = new Image
        {
            Renderable = DefaultAssets.WhiteRegion,
            ZIndex = -1,
            Color = Microsoft.Xna.Framework.Color.DarkGray,
            Width = Screen.Width,
            Height = Screen.Height
        };
        panel.Widgets.Add(background);

        var positionedText = new Label
        {
            Left = 15,
            Top = 10
        };
        panel.Widgets.Add(positionedText);

        var caminfo = new Label
        {
            Left = 10,
            Top = 200
        };
        panel.Widgets.Add(caminfo);

        UpdateSystems.Add(new test_FPSlabelUpdate(World, this, positionedText, "FPS: "));
        UpdateSystems.Add(new test_CameraControlSystem(World, this, caminfo));

        var tips = new Label
        {
            Left = 10,
            Top = 50,
            Text = " Press: \'T\' to toggle Full Screen\n Press: \'C\' to toggle Cursor Display and Lock the Cursor in the center\n\n Press: \'Esc\' to Exit" +
            "\n\nWhen Cursor Hide: WASD to move, Space and LeftCtrl for up and down."
        };
        panel.Widgets.Add(tips);

        var uiwidgetSceneButton = new ImageTextButton
        {
            Margin = new Myra.Graphics2D.Thickness(10),
            Padding = new Myra.Graphics2D.Thickness(3),
            Text = "UI widget Scene",
            HorizontalAlignment = HorizontalAlignment.Right,
            VerticalAlignment = VerticalAlignment.Top
        };
        uiwidgetSceneButton.TouchDown += (s, a) =>
        {
            var uiscene = new UIWidgetsScene(engine);
            engine.AddSceneToHandle(uiscene.NAME, uiscene);

            UnLoad();
        };
        panel.Widgets.Add(uiwidgetSceneButton);

        testLabel = new Label
        {
            Left = 500,
            Top = 500,
        };
        panel.Widgets.Add(testLabel);

        RootWidget = () => panel;

        lerpBg = Screen.ShowCursor ? 1 : 0;
    }

    int updateCount = 0;
    public override void Update(Microsoft.Xna.Framework.GameTime gameTime)
    {
        base.Update(gameTime);

        _desktop.Root = RootWidget();
        updateCount++;
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    float Lerp(float A, float B, float t)
    {
        return A + (B - A) * t;
    }

    float lerpBg = 0;
    int renderCount = 0;
    public override void Render(in Microsoft.Xna.Framework.GraphicsDeviceManager gdm, Microsoft.Xna.Framework.GameTime gameTime, int tick)
    {
        renderCount++;
        testLabel.Text = "__u: " + updateCount + "   r: " + renderCount + " - " + (updateCount - renderCount);
        //var rendertargettest = new RenderTarget2D(gdm.GraphicsDevice, Screen.Width, Screen.Height);
        //gdm.GraphicsDevice.SetRenderTarget(rendertargettest);
        //foreach (var rt in gdm.GraphicsDevice.GetRenderTargets())
        //{
        //    testLabel.Text += "\n rt:" + rt.ToString();
        //}

        gdm.GraphicsDevice.Clear(Microsoft.Xna.Framework.Color.CadetBlue);

        base.Render(gdm, gameTime, tick);

        //gdm.GraphicsDevice.SetRenderTarget(null);
        //SpriteBatch.Begin();
        //SpriteBatch.Draw(rendertargettest, new Vector2(0, 0), Screen.ScreenRect, Microsoft.Xna.Framework.Color.White);
        //SpriteBatch.End();

        lerpBg = Lerp(lerpBg, Screen.ShowCursor ? 1 : 0, (float)(gameTime.ElapsedGameTime.TotalMilliseconds / 600));

        background.Opacity = Lerp(0, 0.7f, lerpBg);
        background.Width = Screen.Width;
        background.Height = Screen.Height;

        gdm.GraphicsDevice.Viewport = new Viewport(0, 0, Screen.Width, Screen.Height);

        _desktop.Render();

    }

    public void UnLoad()
    {
        ToUnload = true;

        UpdatePause = true;
        TickPause = true;
        RenderPause = true;
    }

    public override void Dispose()
    {
        _desktop?.Dispose();

        base.Dispose();
    }
}
